package com.meeruu.sg.account.core.domain.facade.impl;

import com.alibaba.fastjson.JSON;
import com.meeruu.common.model.error.BaseCode;
import com.meeruu.common.model.result.BaseRpcResult;
import com.meeruu.common.utils.LoggerUtil;
import com.meeruu.sg.account.core.api.dto.request.oper.*;
import com.meeruu.sg.account.core.api.exception.AccountException;
import com.meeruu.sg.account.core.api.exception.ErrorCode;
import com.meeruu.sg.account.core.api.service.IAccountHandleService;
import com.meeruu.sg.account.core.domain.biz.AccountHandleBiz;
import com.meeruu.sg.account.core.domain.component.lock.BizLock;
import com.meeruu.sg.account.core.domain.component.lock.LockTemplate;
import com.meeruu.sg.account.core.domain.util.AssertUtils;
import com.meeruu.summerframework.cloud.anno.MRSCProvider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Auther: liwu
 * @Date: 2019/5/16 16:49
 * @Description:
 */
@Slf4j
@MRSCProvider(serviceInterface = IAccountHandleService.class)
@Component
public class AccountHandleServiceImpl implements IAccountHandleService {

    @Autowired
    private AccountHandleBiz accountHandleBiz;

    @Autowired
    private LockTemplate lockTemplate;

    // 单应用40个线程，每个线程1000一次处理1000条数据，一次处理40 * 1000 = 4W 条，一共280W
    // 作用：防止数据库连接池被占满
    private ExecutorService executorService = Executors.newFixedThreadPool(40);

    @Override
    public BaseRpcResult<String> openAccount(OpenAccountRequest request) {
        LoggerUtil.info(log, "开户请求开始,param openAccountRequest: %s", JSON.toJSONString(request));

        try {

            this.checkOpenAccountParam(request);
            String lock = getLock(request);

            return lockTemplate.execute(BizLock.builder()
                            .bizType("openAccount")
                            .bizId(lock)
                            .method("openAccount")
                            .expire(15)
                            .build()
                    , () -> {

                        String accountId = accountHandleBiz.openAccount(request);
                        return new BaseRpcResult<>(accountId);
                    });


        } catch (AccountException f) {

            LoggerUtil.error(log, "开户异常,param openAccountRequest: %s", f, JSON.toJSONString(request));
            return new BaseRpcResult<String>().error(f.getCode(), "开户异常:" + f.getMessage());
        } catch (Throwable ex) {

            LoggerUtil.error(log, "开户异常,param openAccountRequest: %s", ex, JSON.toJSONString(request));
            return new BaseRpcResult<String>().error(BaseCode.SYSTEM_FAILD.getCode(), ex.getMessage());
        }

    }


    @Override
    public BaseRpcResult<Void> dealAccount(DealAccountRequest request) {
        LoggerUtil.info(log, "账户状态变更请求开始,param dealAccountRequest: %s", JSON.toJSONString(request));

        try {

            this.checkDealAccountParam(request);
            accountHandleBiz.dealAccount(request);
            return new BaseRpcResult<>();
        } catch (AccountException f) {

            LoggerUtil.error(log, "账户状态变更异常,param dealAccountRequest: %s", f, JSON.toJSONString(request));
            return new BaseRpcResult<Void>().error(f.getCode(), "账户状态变更异常:" + f.getMessage());
        } catch (Throwable ex) {

            LoggerUtil.error(log, "账户状态变更异常,param dealAccountRequest: %s", ex, JSON.toJSONString(request));
            return new BaseRpcResult<Void>().error(BaseCode.SYSTEM_FAILD.getCode(), ex.getMessage());
        }

    }


    @Override
    public BaseRpcResult<Void> accountCancellation(LogoutAccountRequest request) {
        try {
            accountHandleBiz.accountCancellation(request);
            return new BaseRpcResult<>();
        } catch (Exception e) {
            LoggerUtil.error(log, "账户注销异常,param dealAccountRequest: %s", e, JSON.toJSONString(request));
            return new BaseRpcResult<Void>().error(BaseCode.SYSTEM_FAILD.getCode(), e.getMessage());
        }
    }


    @Override
    public BaseRpcResult<Boolean> updateOrgAccountInfo(UpdateOrgAccountRequest request) {
        LoggerUtil.info(log, "更新账户信息,param updateOrgAccountInfo: %s", JSON.toJSONString(request));

        try {
            AssertUtils.isTrue(request == null || StringUtils.isEmpty(request.getAccountId()), BaseCode.PARAM_ERROR.getCode(), "账户id不能为空");
            boolean result = accountHandleBiz.updateOrgAccount(request);
            return new BaseRpcResult<>(result);
        } catch (AccountException f) {

            LoggerUtil.error(log, "账户状态变更异常,param updateOrgAccountInfo: %s", f, JSON.toJSONString(request));
            return new BaseRpcResult<>(false).error(f.getCode(), "账户状态变更异常:" + f.getMessage());
        } catch (Throwable ex) {

            LoggerUtil.error(log, "账户状态变更异常,param updateOrgAccountInfo: %s", ex, JSON.toJSONString(request));
            return new BaseRpcResult<>(false).error(BaseCode.SYSTEM_FAILD.getCode(), ex.getMessage());
        }
    }

    @Override
    public BaseRpcResult<Void> syncUserAccountBatch(List<SyncUserAccount> userAccounts) {
        executorService.execute(() -> {
            try {
                accountHandleBiz.syncUserAccountBatch(userAccounts);
                LoggerUtil.info(log, "同步用户账户完成");
            } catch (Exception e) {
                LoggerUtil.error(log, "数据同步失败", e);
            }
        });
        return new BaseRpcResult<>();
    }


    /**
     * 开户参数校验
     */
    private void checkOpenAccountParam(OpenAccountRequest request) {
        AssertUtils.isTrue(null == request, ErrorCode.PARAM_ERROR.getCode(), "开户信息不能为空");
        AssertUtils.isTrue(StringUtils.isEmpty(request.getAccountOpenDate()), ErrorCode.PARAM_ERROR.getCode(), "开户时间不能为空");
        AssertUtils.isTrue(StringUtils.isEmpty((request).getAccountType()), ErrorCode.PARAM_ERROR.getCode(), "开户 accountType不能为空");
        if (request instanceof UserOpenAccountRequest) {
            // 用户账户开户
            AssertUtils.isTrue(StringUtils.isEmpty(((UserOpenAccountRequest) request).getUserCode()), ErrorCode.PARAM_ERROR.getCode(), "用户开户 userCode不能为空");

        } else if (request instanceof MerchantOpenAccountRequest) {
            // 商家账户开户
            AssertUtils.isTrue(StringUtils.isEmpty(((MerchantOpenAccountRequest) request).getMerchantCode()), ErrorCode.PARAM_ERROR.getCode(), "商家开户 merchantCode不能为空");

        } else if (request instanceof OrgOpenAccountRequest) {
            // 机构账户开户
            AssertUtils.isTrue(StringUtils.isEmpty(request.getAccountName()), ErrorCode.PARAM_ERROR.getCode(), "机构开户 accountName不能为空");
            AssertUtils.isTrue(StringUtils.isEmpty(((OrgOpenAccountRequest) request).getAccountUsage()), ErrorCode.PARAM_ERROR.getCode(), "机构开户 accountUsage不能为空");

        } else {
            LoggerUtil.error(log, "没有找到对应的账户请求类型 %s", JSON.toJSONString(request));
            throw new AccountException(ErrorCode.BIZ_ACCOUNT_REQUEST_NOT_EXIST.getCode(), ErrorCode.BIZ_ACCOUNT_REQUEST_NOT_EXIST.getMessage());
        }

    }

    /**
     * 开户加锁
     */
    private String getLock(OpenAccountRequest request) {
        String lock;
        if (request instanceof UserOpenAccountRequest) {
            lock = ((UserOpenAccountRequest) request).getUserCode();

        } else if (request instanceof MerchantOpenAccountRequest) {
            lock = ((MerchantOpenAccountRequest) request).getMerchantCode();

        } else if (request instanceof OrgOpenAccountRequest) {
            lock = ((OrgOpenAccountRequest) request).getAccountName();

        } else {
            LoggerUtil.error(log, "没有找到对应的账户请求类型 %s", JSON.toJSONString(request));
            throw new AccountException(ErrorCode.BIZ_ACCOUNT_REQUEST_NOT_EXIST.getCode(), ErrorCode.BIZ_ACCOUNT_REQUEST_NOT_EXIST.getMessage());
        }
        return lock;
    }


    /**
     * 账户状态变更参数检查
     */
    private void checkDealAccountParam(DealAccountRequest request) {
        AssertUtils.isTrue(null == request, ErrorCode.PARAM_ERROR.getCode(), "账户状态变更信息不能为空");
        AssertUtils.isTrue(StringUtils.isEmpty(request.getAccountId()), ErrorCode.PARAM_ERROR.getCode(), "accountId 不能为空");
        AssertUtils.isTrue(StringUtils.isEmpty(request.getAccountOprType()), ErrorCode.PARAM_ERROR.getCode(), "accountOprType 不能为空");
        AssertUtils.isTrue(StringUtils.isEmpty(request.getAccountGroup()), ErrorCode.PARAM_ERROR.getCode(), "accountGroup 不能为空");
//        AssertUtils.isTrue(StringUtils.isEmpty(request.getAccountType()), ErrorCode.PARAM_ERROR.getCode(), "accountType 不能为空");
    }


}


